/**
 * Copyright (C) 2011 The Android Open Source Project 
 * Emial : guoyil199@163.com
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */ 
package com.google.android.zxing;

import java.io.IOException;
import java.util.Hashtable;
import java.util.Vector;

import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.graphics.Bitmap;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.Vibrator;
import android.support.v7.app.ActionBarActivity;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

import com.android.lib.app.Log;
import com.google.android.zxing.camera.CameraManager;
import com.google.android.zxing.decoding.CaptureActivityHandler;
import com.google.android.zxing.decoding.InactivityTimer;
import com.google.android.zxing.view.ViewfinderView;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.ReaderException;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;

/**
 * @author Administrator
 * @Email guoyil199@163.com
 * @version V1.0
 * @Date 2015年3月17日 下午3:59:48
 * @Title <pre>
 * Zxing 扫描Activity
 * </pre>
 * @Description <pre>
 * 需要权限
 *  	&ltuses-permission android:name="android.permission.CAMERA" /&gt
 *     &ltuses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /&gt
 *     &ltuses-feature android:name="android.hardware.camera" /&gt
 *     &ltuses-feature android:name="android.hardware.camera.autofocus" /&gt
 *     &ltuses-permission android:name="android.permission.VIBRATE" /&gt
 *     &ltuses-permission android:name="android.permission.FLASHLIGHT" /&gt
 *     &ltuses-permission android:name="android.permission.RECORD_AUDIO" /&gt
 * </pre>
 */
public abstract class AbsZXingAct extends ActionBarActivity/*Activity*/ implements Callback{
	private static final String TAG="AbsZXingAct";
	private CaptureActivityHandler handler;
	private ViewfinderView viewfinderView;
	private boolean hasSurface;
	private Vector<BarcodeFormat> decodeFormats;
	private String characterSet;
	private InactivityTimer inactivityTimer;
	private MediaPlayer mediaPlayer;
	private boolean playBeep;
	private static final float BEEP_VOLUME = 0.10f;
	private boolean vibrate;
	public final static int RESULT_CODE = 1;
	private int viewfinderId;
	private int previewId;
	private boolean isInit=false;
	
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		viewfinderId=getViewFinderId();
		previewId=getPreViewId();
		initCamera();
	}

	public void initCamera() {
		// 初始化 CameraManager
		isInit=true;
		CameraManager.init(this);
		hasSurface = false;
		inactivityTimer = new InactivityTimer(this);
		viewfinderView = (ViewfinderView) findViewById(viewfinderId);
	}
	
	public abstract int getViewFinderId();
	public abstract int getPreViewId();
	
	@SuppressWarnings("deprecation")
	public void startScanQR(){
		if(!isInit){
			initCamera();
		}
		SurfaceView surfaceView = (SurfaceView) findViewById(previewId);
		SurfaceHolder surfaceHolder = surfaceView.getHolder();
		if (hasSurface) {
			initCamera(surfaceHolder);
		} else {
			surfaceHolder.addCallback(this);
			surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		}
		decodeFormats = null;
		characterSet = null;
		playBeep = true;
		AudioManager audioService = (AudioManager) getSystemService(AUDIO_SERVICE);
		if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) {
			playBeep = false;
		}
		initBeepSound();
		vibrate = true;
	}
	
	@Override
	protected void onResume() {
		super.onResume();
	}

	@Override
	protected void onPause() {
		super.onPause();
		if (handler != null) {
			handler.quitSynchronously();
			handler = null;
		}
		CameraManager.get().closeDriver();
	}

	@Override
	protected void onDestroy() {
		CameraManager.get().closeDriver();
		inactivityTimer.shutdown();
		super.onDestroy();
	}

	private void initCamera(SurfaceHolder surfaceHolder) {
		try {
			CameraManager.get().openDriver(surfaceHolder);
		} catch (IOException ioe) {
			return;
		} catch (RuntimeException e) {
			return;
		}
		if (handler == null) {
			handler = new CaptureActivityHandler(this, decodeFormats,characterSet);
		}
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		if (!hasSurface) {
			hasSurface = true;
			initCamera(holder);
		}
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		hasSurface = false;
	}

	public ViewfinderView getViewfinderView() {
		if(null == viewfinderView){
			viewfinderView = (ViewfinderView) findViewById(viewfinderId);
		}
		return viewfinderView;
	}

	public Handler getHandler() {
		return handler;
	}

	public void drawViewfinder() {
		if(null!=viewfinderView)
			viewfinderView.drawViewfinder();
	}

	public abstract void decodeResult(com.google.zxing.Result reslt,Bitmap barcode);
	
	public void handleDecode(Result obj, Bitmap barcode) {
		inactivityTimer.onActivity();
		playBeepSoundAndVibrate();
		decodeResult(obj, barcode);
	}

	private void initBeepSound() {
		if (playBeep && mediaPlayer == null) {
			// The volume on STREAM_SYSTEM is not adjustable, and users found it
			// too loud,
			// so we now play on the music stream.
			setVolumeControlStream(AudioManager.STREAM_MUSIC);
			mediaPlayer = new MediaPlayer();
			mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
			mediaPlayer.setOnCompletionListener(beepListener);

			AssetFileDescriptor file = getResources().openRawResourceFd(R.raw.beep);
			try {
				mediaPlayer.setDataSource(file.getFileDescriptor(),
						file.getStartOffset(), file.getLength());
				file.close();
				mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
				mediaPlayer.prepare();
			} catch (IOException e) {
				mediaPlayer = null;
			}
		}
	}

	private static final long VIBRATE_DURATION = 200L;

	private void playBeepSoundAndVibrate() {
		if (playBeep && mediaPlayer != null) {
			mediaPlayer.start();
		}
		if (vibrate) {
			Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
			vibrator.vibrate(VIBRATE_DURATION);
		}
	}

	/**
	 * When the beep has finished playing, rewind to queue up another one.
	 */
	private final OnCompletionListener beepListener = new OnCompletionListener() {
		public void onCompletion(MediaPlayer mediaPlayer) {
			mediaPlayer.seekTo(0);
		}
	};

	public String decodeByQRBitmap(Bitmap bitmap) {
		if (bitmap == null) {
			Log.e(TAG,"Bitmap is null ");
			return "null";
		}
		Hashtable<DecodeHintType, Object> hints = null;
		initHints(hints, null, "UTF8");// 注意不要写成UTF-8，因为它里面自己包装的是UTF8
		MultiFormatReader multiFormatReader = new MultiFormatReader();
		multiFormatReader.setHints(hints);
		LuminanceSource source = new BitmapLuance(bitmap);
		BinaryBitmap bit = new BinaryBitmap(new HybridBinarizer(source));
		try {
			return multiFormatReader.decodeWithState(bit).getText();
		} catch (ReaderException re) {
			Log.e(TAG,re.getMessage());
			// continue
		} finally {
			multiFormatReader.reset();
		}
		return null;
	}

	public void initHints(Hashtable<DecodeHintType, Object> hints,
			Vector<BarcodeFormat> decodeFormats, String CODE_STYLE) {
		hints = new Hashtable<DecodeHintType, Object>(2);
		if (decodeFormats == null || decodeFormats.isEmpty()) {
			decodeFormats = new Vector<BarcodeFormat>();
			decodeFormats.addAll(MyDecodeFormatManager.ONE_D_FORMATS);
			decodeFormats.addAll(MyDecodeFormatManager.QR_CODE_FORMATS);
			decodeFormats.addAll(MyDecodeFormatManager.DATA_MATRIX_FORMATS);
		}
		hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats);
		if (CODE_STYLE != null) {
			Log.e(TAG, "initHints code style is null");
			// 下面这句不加编码方式更方便，让它自己查找。当然效率可能要低一些，但适用性更广
			// hints.put(DecodeHintType.CHARACTER_SET, CODE_STYLE);
		}
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		//if (resultCode != RESULT_OK)return;
	}

	public Intent getImagePickIntent() {
		Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
		intent.setType("image/*");
		return intent;
	}
}
